#include <iostream>
#include <memory>
#include <functional>
#include "TcpServer.hpp"
#include "Protocol.hpp"
#include "CalCulate.hpp"

using namespace std;
using namespace protocol_ns;

void Usage(string proc)
{
    cout << "Usage: " << proc << " + port" << endl;
}

using callback_t = function<Response(const Request &req)>;

class CalService
{
public:
    CalService(callback_t cb):_cb(cb)
    {}
    void Server(socket_sptr sockptr, InetAddr client)
    {
        int sockfd = sockptr->Sockfd();
        LOG(DEBUG, "get a new link sockfd: %d, %s:%d", sockfd, client.Ip().c_str(), to_string(client.Port()));
        string clientaddr = "[" + client.Ip() + ":" + to_string(client.Port()) + "]# ";

        string inbuffer;
        while (true)
        {
            Request req;
            // 1、读取数据
            int n = sockptr->Recv(&inbuffer);
            if (n < 0)
            {
                LOG(DEBUG, "client %s quit", clientaddr.c_str());
                break;
            }
            // 2、分析数据
            string package = Decode(inbuffer);
            if (package.empty())
                continue;

            cout << "res string: \n" << package << endl;
            // 3、反序列化
            req.Deserialize(package);
            // 4、业务处理
            Response resp = _cb(req);

            // 5、对应答序列化
            string send_str;
            resp.Serialize(&send_str);
            cout << "resp Serialize: " << endl;
            cout << send_str << endl;

            // 6、添加长度报头
            send_str = Encode(send_str);
            cout << "resp Encode: " << endl;
            cout << send_str << endl;

            // 7、这次不对发送做处理   epoll
            sockptr->Send(send_str);
        }
    }
    ~CalService()
    {}
private:
    callback_t _cb;
};

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        Usage(argv[0]);
        exit(1);
    }
    uint16_t port = stoi(argv[1]);
    CalCulate cal;
    CalService calservice(bind(&CalCulate::Excute, &cal, placeholders::_1));
    io_service_t service = bind(&CalService::Server, &calservice, 
       placeholders::_1, placeholders::_2);

    unique_ptr<TcpServer> ts = make_unique<TcpServer>(port, service);
    ts->Loop();

    return 0;
}